home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / ncurses / tty / lib_twait.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  11.7 KB  |  441 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  31.  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
  32.  ****************************************************************************/
  33.  
  34. /*
  35. **    lib_twait.c
  36. **
  37. **    The routine _nc_timed_wait().
  38. **
  39. **    (This file was originally written by Eric Raymond; however except for
  40. **    comments, none of the original code remains - T.Dickey).
  41. */
  42.  
  43. #include <curses.priv.h>
  44.  
  45. #ifdef __BEOS__
  46. #undef false
  47. #undef true
  48. #include <OS.h>
  49. #endif
  50.  
  51. #if USE_FUNC_POLL
  52. # if HAVE_SYS_TIME_H
  53. #  include <sys/time.h>
  54. # endif
  55. #elif HAVE_SELECT
  56. # if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
  57. #  include <sys/time.h>
  58. # endif
  59. # if HAVE_SYS_SELECT_H
  60. #  include <sys/select.h>
  61. # endif
  62. #endif
  63.  
  64. MODULE_ID("$Id: lib_twait.c,v 1.46 2002/09/01 00:28:18 tom Exp $")
  65.  
  66. static long
  67. _nc_gettime(bool first)
  68. {
  69.     long res;
  70.  
  71. #if HAVE_GETTIMEOFDAY
  72. # define PRECISE_GETTIME 1
  73.     static struct timeval t0;
  74.     struct timeval t1;
  75.     gettimeofday(&t1, (struct timezone *) 0);
  76.     if (first) {
  77.     t0 = t1;
  78.     }
  79.     res = (t1.tv_sec - t0.tv_sec) * 1000
  80.     + (t1.tv_usec - t0.tv_usec) / 1000;
  81. #else
  82. # define PRECISE_GETTIME 0
  83.     static time_t t0;
  84.     time_t t1 = time((time_t *) 0);
  85.     if (first) {
  86.     t0 = t1;
  87.     }
  88.     res = (t1 - t0) * 1000;
  89. #endif
  90.     TR(TRACE_IEVENT, ("%s time: %ld msec", first ? "get" : "elapsed", res));
  91.     return res;
  92. }
  93.  
  94. #ifdef NCURSES_WGETCH_EVENTS
  95. NCURSES_EXPORT(int)
  96. _nc_eventlist_timeout(_nc_eventlist * evl)
  97. {
  98.     _nc_event **ev, **last;
  99.     int event_delay = -1;
  100.  
  101.     if (evl != 0) {
  102.  
  103.     ev = evl->events;
  104.     last = ev + evl->count;
  105.  
  106.     while (ev < last) {
  107.         if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC) {
  108.         event_delay = (*ev)->data.timeout_msec;
  109.         if (event_delay < 0)
  110.             event_delay = LONG_MAX;    /* FIXME Is this defined? */
  111.         }
  112.     }
  113.     }
  114.     return event_delay;
  115. }
  116. #endif /* NCURSES_WGETCH_EVENTS */
  117.  
  118. /*
  119.  * Wait a specified number of milliseconds, returning nonzero if the timer
  120.  * didn't expire before there is activity on the specified file descriptors.
  121.  * The file-descriptors are specified by the mode:
  122.  *    0 - none (absolute time)
  123.  *    1 - ncurses' normal input-descriptor
  124.  *    2 - mouse descriptor, if any
  125.  *    3 - either input or mouse.
  126.  *
  127.  * Experimental:  if NCURSES_WGETCH_EVENTS is defined, (mode & 4) determines
  128.  * whether to pay attention to evl argument.  If set, the smallest of
  129.  * millisecond and of timeout of evl is taken.
  130.  *
  131.  * We return a mask that corresponds to the mode (e.g., 2 for mouse activity).
  132.  *
  133.  * If the milliseconds given are -1, the wait blocks until activity on the
  134.  * descriptors.
  135.  */
  136. NCURSES_EXPORT(int)
  137. _nc_timed_wait(int mode,
  138.            int milliseconds,
  139.            int *timeleft
  140.            EVENTLIST_2nd(_nc_eventlist * evl))
  141. {
  142.     int fd;
  143.     int count;
  144.     int result;
  145.  
  146. #ifdef NCURSES_WGETCH_EVENTS
  147.     int timeout_is_event = 0;
  148. #endif
  149.  
  150. #if USE_FUNC_POLL
  151.     struct pollfd fd_list[2];
  152.     struct pollfd *fds = fd_list;
  153. #elif defined(__BEOS__)
  154. #elif HAVE_SELECT
  155.     static fd_set set;
  156. #endif
  157.  
  158.     long starttime, returntime;
  159.  
  160.     TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
  161.               milliseconds, mode));
  162.  
  163. #ifdef NCURSES_WGETCH_EVENTS
  164.     if (mode & 4) {
  165.     int event_delay = _nc_eventlist_timeout(evl);
  166.  
  167.     if (event_delay >= 0
  168.         && (milliseconds >= event_delay || milliseconds < 0)) {
  169.         milliseconds = event_delay;
  170.         timeout_is_event = 1;
  171.     }
  172.     }
  173. #endif
  174.  
  175. #if PRECISE_GETTIME
  176.   retry:
  177. #endif
  178.     starttime = _nc_gettime(TRUE);
  179.  
  180.     count = 0;
  181.  
  182. #ifdef NCURSES_WGETCH_EVENTS
  183.     if ((mode & 4) && evl)
  184.     evl->result_flags = 0;
  185. #endif
  186.  
  187. #if USE_FUNC_POLL
  188.     memset(fd_list, 0, sizeof(fd_list));
  189.  
  190. #ifdef NCURSES_WGETCH_EVENTS
  191.     if ((mode & 4) && evl)
  192.     fds = typeMalloc(struct pollfd, 2 + evl->count);
  193. #endif
  194.  
  195.     if (mode & 1) {
  196.     fds[count].fd = SP->_ifd;
  197.     fds[count].events = POLLIN;
  198.     count++;
  199.     }
  200.     if ((mode & 2)
  201.     && (fd = SP->_mouse_fd) >= 0) {
  202.     fds[count].fd = fd;
  203.     fds[count].events = POLLIN;
  204.     count++;
  205.     }
  206. #ifdef NCURSES_WGETCH_EVENTS
  207.     if ((mode & 4) && evl) {
  208.     _nc_event **ev = evl->events;
  209.     _nc_event **last = ev + evl->count;
  210.  
  211.     while (ev < last) {
  212.         if ((*ev)->type == _NC_EVENT_FILE
  213.         && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) {
  214.         fds[count].fd = (*ev)->data.fev.fd;
  215.         fds[count].events = POLLIN;
  216.         count++;
  217.         }
  218.     }
  219.     }
  220. #endif
  221.  
  222.     result = poll(fds, count, milliseconds);
  223.  
  224. #ifdef NCURSES_WGETCH_EVENTS
  225.     if ((mode & 4) && evl) {
  226.     _nc_event **ev = evl->events;
  227.     _nc_event **last = ev + evl->count;
  228.     int c;
  229.  
  230.     if (!result)
  231.         count = 0;
  232.     while (ev < last) {
  233.         if ((*ev)->type == _NC_EVENT_FILE
  234.         && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) {
  235.         (*ev)->data.fev.result = 0;
  236.         for (c = 0; c < count; c++)
  237.             if (fds[c].fd == (*ev)->data.fev.fd
  238.             && fds[c].revents & POLLIN) {
  239.             (*ev)->data.fev.result |= _NC_EVENT_FILE_READABLE;
  240.             evl->result_flags |= _NC_EVENT_FILE_READABLE;
  241.             }
  242.         } else if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC
  243.                && !result && timeout_is_event) {
  244.         evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC;
  245.         }
  246.     }
  247.     }
  248.  
  249.     if (fds != fd_list)
  250.     free((char *) fds);
  251.  
  252. #endif
  253.  
  254. #elif defined(__BEOS__)
  255.     /*
  256.      * BeOS's select() is declared in socket.h, so the configure script does
  257.      * not see it.  That's just as well, since that function works only for
  258.      * sockets.  This (using snooze and ioctl) was distilled from Be's patch
  259.      * for ncurses which uses a separate thread to simulate select().
  260.      *
  261.      * FIXME: the return values from the ioctl aren't very clear if we get
  262.      * interrupted.
  263.      *
  264.      * FIXME: this assumes mode&1 if milliseconds < 0 (see lib_getch.c).
  265.      */
  266.     result = 0;
  267.     if (mode & 1) {
  268.     int step = (milliseconds < 0) ? 0 : 5000;
  269.     bigtime_t d;
  270.     bigtime_t useconds = milliseconds * 1000;
  271.     int n, howmany;
  272.  
  273.     if (useconds <= 0)    /* we're here to go _through_ the loop */
  274.         useconds = 1;
  275.  
  276.     for (d = 0; d < useconds; d += step) {
  277.         n = 0;
  278.         howmany = ioctl(0, 'ichr', &n);
  279.         if (howmany >= 0 && n > 0) {
  280.         result = 1;
  281.         break;
  282.         }
  283.         if (useconds > 1 && step > 0) {
  284.         snooze(step);
  285.         milliseconds -= (step / 1000);
  286.         if (milliseconds <= 0) {
  287.             milliseconds = 0;
  288.             break;
  289.         }
  290.         }
  291.     }
  292.     } else if (milliseconds > 0) {
  293.     snooze(milliseconds * 1000);
  294.     milliseconds = 0;
  295.     }
  296. #elif HAVE_SELECT
  297.     /*
  298.      * select() modifies the fd_set arguments; do this in the
  299.      * loop.
  300.      */
  301.     FD_ZERO(&set);
  302.  
  303.     if (mode & 1) {
  304.     FD_SET(SP->_ifd, &set);
  305.     count = SP->_ifd + 1;
  306.     }
  307.     if ((mode & 2)
  308.     && (fd = SP->_mouse_fd) >= 0) {
  309.     FD_SET(fd, &set);
  310.     count = max(fd, count) + 1;
  311.     }
  312. #ifdef NCURSES_WGETCH_EVENTS
  313.     if ((mode & 4) && evl) {
  314.     _nc_event **ev = evl->events;
  315.     _nc_event **last = ev + evl->count;
  316.  
  317.     while (ev < last) {
  318.         if ((*ev)->type == _NC_EVENT_FILE
  319.         && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) {
  320.         FD_SET((*ev)->data.fev.fd, &set);
  321.         count = max((*ev)->data.fev.fd + 1, count);
  322.         }
  323.     }
  324.     }
  325. #endif
  326.  
  327.     if (milliseconds >= 0) {
  328.     struct timeval ntimeout;
  329.     ntimeout.tv_sec = milliseconds / 1000;
  330.     ntimeout.tv_usec = (milliseconds % 1000) * 1000;
  331.     result = select(count, &set, NULL, NULL, &ntimeout);
  332.     } else {
  333.     result = select(count, &set, NULL, NULL, NULL);
  334.     }
  335.  
  336. #ifdef NCURSES_WGETCH_EVENTS
  337.     if ((mode & 4) && evl) {
  338.     _nc_event **ev = evl->events;
  339.     _nc_event **last = ev + evl->count;
  340.  
  341.     evl->result_flags = 0;
  342.     while (ev < last) {
  343.         if ((*ev)->type == _NC_EVENT_FILE
  344.         && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) {
  345.         (*ev)->data.fev.result = 0;
  346.         if (FD_ISSET((*ev)->data.fev.fd, &set)) {
  347.             (*ev)->data.fev.result |= _NC_EVENT_FILE_READABLE;
  348.             evl->result_flags |= _NC_EVENT_FILE_READABLE;
  349.         }
  350.         } else if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC
  351.                && !result && timeout_is_event)
  352.         evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC;
  353.     }
  354.     }
  355. #endif
  356.  
  357. #endif /* USE_FUNC_POLL, etc */
  358.  
  359.     returntime = _nc_gettime(FALSE);
  360.  
  361.     if (milliseconds >= 0)
  362.     milliseconds -= (returntime - starttime);
  363.  
  364. #ifdef NCURSES_WGETCH_EVENTS
  365.     if (evl) {
  366.     _nc_event **ev = evl->events;
  367.     _nc_event **last = ev + evl->count;
  368.  
  369.     evl->result_flags = 0;
  370.     while (ev < last) {
  371.         if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC) {
  372.         long diff = (returntime - starttime);
  373.         if ((*ev)->data.timeout_msec <= diff)
  374.             (*ev)->data.timeout_msec = 0;
  375.         else
  376.             (*ev)->data.timeout_msec -= diff;
  377.         }
  378.  
  379.     }
  380.     }
  381. #endif
  382.  
  383. #if PRECISE_GETTIME
  384.     /*
  385.      * If the timeout hasn't expired, and we've gotten no data,
  386.      * this is probably a system where 'select()' needs to be left
  387.      * alone so that it can complete.  Make this process sleep,
  388.      * then come back for more.
  389.      */
  390.     if (result == 0 && milliseconds > 100) {
  391.     napms(100);
  392.     milliseconds -= 100;
  393.     goto retry;
  394.     }
  395. #endif
  396.  
  397.     /* return approximate time left in milliseconds */
  398.     if (timeleft)
  399.     *timeleft = milliseconds;
  400.  
  401.     TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
  402.               result, errno, milliseconds));
  403.  
  404.     /*
  405.      * Both 'poll()' and 'select()' return the number of file descriptors
  406.      * that are active.  Translate this back to the mask that denotes which
  407.      * file-descriptors, so that we don't need all of this system-specific
  408.      * code everywhere.
  409.      */
  410.     if (result != 0) {
  411.     if (result > 0) {
  412.         result = 0;
  413. #if USE_FUNC_POLL
  414.         for (count = 0; count < 2; count++) {
  415.         if ((mode & (1 << count))
  416.             && (fds[count].revents & POLLIN)) {
  417.             result |= (1 << count);
  418.         }
  419.         }
  420. #elif defined(__BEOS__)
  421.         result = 1;        /* redundant, but simple */
  422. #elif HAVE_SELECT
  423.         if ((mode & 2)
  424.         && (fd = SP->_mouse_fd) >= 0
  425.         && FD_ISSET(fd, &set))
  426.         result |= 2;
  427.         if ((mode & 1)
  428.         && FD_ISSET(SP->_ifd, &set))
  429.         result |= 1;
  430. #endif
  431.     } else
  432.         result = 0;
  433.     }
  434. #ifdef NCURSES_WGETCH_EVENTS
  435.     if ((mode & 4) && evl && evl->result_flags)
  436.     result |= 4;
  437. #endif
  438.  
  439.     return (result);
  440. }
  441.